package com.example.com.common.utils;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;

import com.example.com.common.utils.bean.Size;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 图片的压缩处理工具类
 */
public class BitmapUtils {
    public static boolean checkSDCardAvailable() {
        return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
    }

    public static boolean saveBitmapToFile(Bitmap photoBitmap, File outFile) {
        if (checkSDCardAvailable()) {
            if (outFile.exists()) {
                outFile.delete();
            }
            File dir = outFile.getParentFile();
            if (!dir.exists()) {
                dir.mkdirs();
            }
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(outFile);
                if (photoBitmap != null) {
                    if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
                        fileOutputStream.flush();
                        return true;
                    }
                }
            } catch (Exception e) {
                outFile.delete();
                e.printStackTrace();
            } finally {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 质量压缩 存为文件
     * sizeB 大约占用字节 0表示不压缩质量
     */
    public static void compressQualityToFile(Bitmap src, int sizeByte, File outFile, Bitmap.CompressFormat format) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        src.compress(format, 100, baos);// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 100;
        while (sizeByte > 0 && baos.toByteArray().length > sizeByte && options > 20) { // 循环判断如果压缩后图片是否大于100kb而且质量在20以上大于继续压缩
            baos.reset();// 重置baos即清空baos
            options -= 10;// 每次都减少10
            src.compress(format, options, baos);// 这里压缩options%，把压缩后的数据存放到baos中
        }
        byte[] byteArr = baos.toByteArray();
        try {
            if (outFile.exists()) {
                outFile.delete();
            }
            FileOutputStream fileOutputStream = new FileOutputStream(outFile);
            fileOutputStream.write(byteArr);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        try {
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 质量压缩 返回bitmap
     * sizeB 大约占用字节 0表示不压缩质量
     */
    public static Bitmap compressQualityToBitmap(Bitmap srcBitmap, int sizeByte, Bitmap.CompressFormat format) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        srcBitmap.compress(format, 100, baos);// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length > sizeByte && options > 20) { // 循环判断如果压缩后图片是否大于100kb而且质量在20以上大于继续压缩
            baos.reset();// 重置baos即清空baos
            options -= 10;// 每次都减少10
            srcBitmap.compress(format, options, baos);// 这里压缩options%，把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap destBitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
        try {
            isBm.close();
            baos.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
        return destBitmap;

    }
    // decode这个图片并且按比例缩放以减少内存消耗，虚拟机对每张图片的缓存大小也是有限制的

    /**
     * @param file
     * @param width  最大宽
     * @param height 最大高
     * @return
     */
    public static Bitmap decodeFile(File file, int width, int height) {
        try {
            // decode image size
            String filePath = file.getAbsolutePath();
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opts);

            int imgWidth = opts.outWidth;
            int imgHeight = opts.outHeight;
            if (imgWidth == -1 || imgHeight == -1) {
                //有时候获取不到图片宽高
                try {
                    ExifInterface exifInterface = new ExifInterface(filePath);
                    imgHeight = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度
                    imgWidth = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            int scale = 1;
            double scaleX = Math.ceil((float) imgWidth / width);
            double scaleY = Math.ceil((float) imgHeight / height);

            if (scaleX >= scaleY && scaleY > 1) {
                scale = (int) scaleX;
            } else if (scaleY >= scaleX && scaleX > 1) {
                scale = (int) scaleY;
            }
            opts.inJustDecodeBounds = false;
            opts.inSampleSize = scale;
            //the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2
            //即使设置了inSampleSize=7，但是得到的缩略图却是原图的1/4，原因是inSampleSize只能是2的整数次幂，如果不是的话，向下取得最大的2的整数次幂，7向下寻找2的整数次幂，就是4。这样设计的原因很可能是为了渐变bitmap压缩，毕竟按照2的次方进行压缩会比较高效和方便
            Bitmap bitmap = BitmapFactory.decodeFile(filePath, opts);
            return bitmap;
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * @param bitmap
     * @param width  新的宽度
     * @param height 新的高度
     * @return
     */
    public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidth = (float) width / w;
        float scaleHeight = (float) height / h;
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
        return newbmp;
    }

    /**
     * 逻辑是先压长宽，如果存储空间大于了sizeByte，再压质量
     *
     * @param inFile   源文件
     * @param outFile  输出文件
     * @param width    图片最大宽度
     * @param height   图片最大高度
     * @param sizeByte 大约占用字节 传0表示只缩长宽，不压缩质量
     * @return
     */
    public static void compressPicToFile(File inFile, File outFile, int width, int height, int sizeByte) {
        try {
            if (isShouldCompress(inFile, width, height, sizeByte)) {
                Bitmap bitmap = decodeFile(inFile, width, height);
                if (bitmap != null) {
                    bitmap = rotateBitmapByExif(inFile.getAbsolutePath(), bitmap);
                    int imgFormat = FileTypeUtil.getImagesFormat(inFile.getAbsolutePath());
                    Bitmap.CompressFormat format = Bitmap.CompressFormat.PNG;
                    if (FileTypeUtil.JPG == imgFormat) {
                        format = Bitmap.CompressFormat.JPEG;
                    }
                    compressQualityToFile(bitmap, sizeByte, outFile, format);
                }
            } else {
                if (outFile.exists()) {
                    outFile.delete();
                }
                FileUtils.copyFile(inFile, outFile, null);
            }

        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    /**
     * 逻辑是先压长宽，如果存储空间大于了sizeByte，再压质量
     *
     * @param bitmap 源位图
     * @param outFile 输出文件
     * @param width 图片最大宽度
     * @param height 图片最大高度
     * @param sizeByte     大约占用字节 传0表示只缩长宽，不压缩质量
     * @return
     */
    public static void compressPicToFile(Bitmap bitmap, File outFile, int width, int height, int sizeByte, Bitmap.CompressFormat format) {
        if (bitmap != null) {
            try {
                bitmap = zoomBitmap(bitmap, width, height);
                compressQualityToFile(bitmap, sizeByte, outFile, format);
            } catch (Exception e) {
                // TODO: handle exception
            }

        }
    }

    public static void compressPicToFile(Bitmap bitmap, File outFile, int width, int height, int sizeByte) {
        if (bitmap != null) {
            try {
                bitmap = zoomBitmap(bitmap, width, height);
                compressQualityToFile(bitmap, sizeByte, outFile, Bitmap.CompressFormat.PNG);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }

    public static Bitmap compressPicToBitmap(File inFile, int width, int height, int sizeByte) {
        try {
            Bitmap bitmap = decodeFile(inFile, width, height);
            if (bitmap != null) {
                int imgFormat = FileTypeUtil.getImagesFormat(inFile.getAbsolutePath());
                Bitmap.CompressFormat format = Bitmap.CompressFormat.PNG;
                if (FileTypeUtil.JPG == imgFormat) {
                    format = Bitmap.CompressFormat.JPEG;
                }
                return compressQualityToBitmap(bitmap, sizeByte, format);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
        return null;
    }

    public static Bitmap compressPicToBitmap(Bitmap bitmap, int width, int height, int sizeByte) {
        if (bitmap != null) {
            try {
                bitmap = zoomBitmap(bitmap, width, height);
                compressQualityToBitmap(bitmap, sizeByte, Bitmap.CompressFormat.PNG);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        return null;
    }

    public static Bitmap compressPicToBitmap(Bitmap bitmap, int width, int height, int sizeByte, Bitmap.CompressFormat format) {
        if (bitmap != null) {
            try {
                bitmap = zoomBitmap(bitmap, width, height);
                compressQualityToBitmap(bitmap, sizeByte, format);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        return null;
    }

    private static boolean isShouldCompress(File file, int width, int height, int sizeByte) {
        boolean compressByte = false;//是否应压质量
        boolean compressWH = false;//是否应压长宽
        try {
            // decode image size
            String filePath = file.getAbsolutePath();
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opts);
            int imgWidth = opts.outWidth;
            int imgHeight = opts.outHeight;
            if (imgWidth == -1 || imgHeight == -1) {
                //有时候获取不到图片宽高
                try {
                    ExifInterface exifInterface = new ExifInterface(filePath);
                    imgHeight = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度
                    imgWidth = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            compressByte = imgWidth > width || imgHeight > height;
            compressWH = file.length() > sizeByte;
            return compressByte || compressWH;
        } catch (Exception e) {
        }
        return false;
    }


    public static Size getImageSize(String filePath) {
        Size size = null;
        try {
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(filePath, opts);
            size = new Size();
            if (opts.outWidth < 1 || opts.outHeight < 1) {
                //有时候获取不到图片宽高
                try {
                    ExifInterface exifInterface = new ExifInterface(filePath);
                    opts.outHeight = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度
                    opts.outWidth = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            ExifInterface exif = new ExifInterface(filePath);
            int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (ori) {
                case ExifInterface.ORIENTATION_ROTATE_90://旋转了90度
                case ExifInterface.ORIENTATION_ROTATE_270://旋转了270度
                    //这时宽高要交换
                    int tmp = opts.outWidth;
                    opts.outWidth = opts.outHeight;
                    opts.outHeight = tmp;
                    break;
                //ExifInterface.ORIENTATION_NORMAL这个是0度
                //ExifInterface.ORIENTATION_ROTATE_180这个是180度
            }
            size.width = opts.outWidth;
            size.height = opts.outHeight;
        } catch (Exception e) {
        }
        return size;
    }

    public static Bitmap rotateBitmapByExif(String srcPath, Bitmap bitmap) {
        ExifInterface exif;
        Bitmap newBitmap;
        try {
            exif = new ExifInterface(srcPath);
            // 读取图片中相机方向信息
            int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            int degree = 0;
            switch (ori) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
            if (degree != 0) {
                Matrix m = new Matrix();
                m.postRotate(degree);
                newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
                if (bitmap != null)
                    bitmap.recycle();
                return newBitmap;
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }


    /**
     * 裁剪图片通过outUri返回
     *
     * @param activityOrFragment
     *            只能传入Activity Or Fragment
     * @param inUri
     *            输入的Uri
     * @param returnData
     *            是否返回数据
    aspectX aspectY 切图时的比例，传整型
     * @param requestCode
     */
    public static void cropImage(Object activityOrFragment, Uri inUri, Uri outUri, boolean returnData, int aspectX, int aspectY, int requestCode){
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(inUri, "image/*");
        intent.putExtra("crop", "true");
        if(aspectX>0 && aspectY>0) {
            intent.putExtra("aspectX", aspectX);
            intent.putExtra("aspectY", aspectY);
        }
//		intent.putExtra("outputX", outputX);
//		intent.putExtra("outputY", outputY);
        intent.putExtra("scale", true);
        //intent.putExtra("scaleUpIfNeeded", true);这个属性加上输出就一定是outputX*outputY，可能会放大,有的是直接在边上加黑
        //有的手机不加这个属性输出来也一定是outputX*outputY,无论裁剪的时候比例是多少

        intent.putExtra(MediaStore.EXTRA_OUTPUT, outUri);
        intent.putExtra("return-data", returnData);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true); // no face detection
        startActivityForResult(activityOrFragment,intent,requestCode);
    }

    private static void startActivityForResult(Object activityOrFragment,Intent intent,int requestCode){
        if(activityOrFragment instanceof Activity){
            Activity activity = (Activity) activityOrFragment;
            activity.startActivityForResult(intent, requestCode);
        }else if(activityOrFragment instanceof Fragment){
            Fragment fragment = (Fragment) activityOrFragment;
            fragment.startActivityForResult(intent, requestCode);
        }else{
            throw new ClassCastException();
        }
    }
}
